package com;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.bean.BaseModel;
import com.google.common.collect.ArrayListMultimap;

/**
 * 
 * @author zhoufang
 * @version v0.1 2019年7月8日 下午9:33:39  zhoufang
 */
public class ConfigManager {

	public static final String INDEX_SPLIT = "#";
	private static final Map<Class<?>, List<BaseModel>> allList = new ConcurrentHashMap<Class<?>, List<BaseModel>>();
	private static final Map<Class<?>, Map<Object, BaseModel>> primaryMap = new ConcurrentHashMap<Class<?>, Map<Object, BaseModel>>();
	private static final Map<Class<?>, Map<String, ArrayListMultimap<Object, BaseModel>>> indexMap = new ConcurrentHashMap<Class<?>, Map<String, ArrayListMultimap<Object, BaseModel>>>();

	private static ThreadLocal<StringBuilder> sbLocal = new ThreadLocal<StringBuilder>() {
		public StringBuilder get() {
			return new StringBuilder();
		};
	};

	public static void addConfigModel(BaseModel model) {
		addToAllList(model);
		addToPrimaryMap(model);
		addToIndexMap(model);
	}

	private static void addToIndexMap(BaseModel model) {
		if (model.getComplexIndexs() == null || model.getComplexIndexs().length == 0) {
			return;
		}
		Class<? extends BaseModel> clazz = model.getClass();
		Map<String, ArrayListMultimap<Object, BaseModel>> map = indexMap.get(clazz);
		if (map == null) {
			map = new HashMap<String, ArrayListMultimap<Object, BaseModel>>();
			indexMap.put(clazz, map);
		}
		for (String index : model.getComplexIndexs()) {
			ArrayListMultimap<Object, BaseModel> arrayListMultimap = map.get(index);
			if (arrayListMultimap == null) {
				arrayListMultimap = ArrayListMultimap.create();
				map.put(index, arrayListMultimap);
			}
			String[] split = index.split(INDEX_SPLIT);
			Object obj = generateIndexValue(model, split);
			if (obj != null) {
				arrayListMultimap.put(obj, model);
			}
		}
	}

	private static Object generateIndexValue(BaseModel model, String[] split) {
		try {
			if (split.length == 1) {
				return model.getFieldValue(split[0]);
			}
			StringBuilder sb = sbLocal.get();
			for (String str : split) {
				Object fieldValue = model.getFieldValue(str);
				sb.append(fieldValue);
				sb.append(INDEX_SPLIT);
			}
			sb.deleteCharAt(sb.length() - 1);
			return sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private static void addToPrimaryMap(BaseModel model) {
		if (model.getPrimaryKey() == null) {
			return;
		}
		Class<? extends BaseModel> clazz = model.getClass();
		Map<Object, BaseModel> map = primaryMap.get(clazz);
		if (map == null) {
			map = new HashMap<Object, BaseModel>();
			primaryMap.put(clazz, map);
		}
		map.put(model.getPrimaryKey(), model);
	}

	private static void addToAllList(BaseModel model) {
		Class<? extends BaseModel> clazz = model.getClass();
		List<BaseModel> list = allList.get(clazz);
		if (list == null) {
			list = new ArrayList<BaseModel>();
			allList.put(clazz, list);
		}
		list.add(model);
	}

	@SuppressWarnings("unchecked")
	public static <T extends BaseModel> List<T> getAllConfig(Class<T> clazz) {
		List<BaseModel> list = allList.get(clazz);
		return list == null ? null : (List<T>) list;
	}

	@SuppressWarnings("unchecked")
	public static <T extends BaseModel> T getConfigByPrimary(Class<T> clazz, Object obj) {
		Map<Object, BaseModel> map = primaryMap.get(clazz);
		return map == null ? null : (T) map.get(obj);
	}

	@SuppressWarnings("unchecked")
	public static <T extends BaseModel> List<T> getConfigByIndex(Class<T> clazz, String index, Object... objects) {
		Map<String, ArrayListMultimap<Object, BaseModel>> map = indexMap.get(clazz);
		if (map == null) {
			return null;
		}
		ArrayListMultimap<Object, BaseModel> arrayListMultimap = map.get(index);
		if (arrayListMultimap == null) {
			return null;
		}
		if (objects.length == 1) {
			return (List<T>) arrayListMultimap.get(objects[0]);
		}
		StringBuilder builder = sbLocal.get();
		for (Object obj : objects) {
			builder.append(obj);
			builder.append(INDEX_SPLIT);
		}
		builder.deleteCharAt(builder.length() - 1);
		return (List<T>) arrayListMultimap.get(builder.toString());
	}
}
